/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.graphics.surface

import android.app.Instrumentation
import android.graphics.Bitmap
import android.graphics.Color
import android.hardware.HardwareBuffer
import android.os.Build
import android.os.SystemClock
import android.view.Window
import androidx.annotation.RequiresApi
import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert

@SdkSuppress(minSdkVersion = 29)
internal class SurfaceControlUtils {
    companion object {

        @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
        fun validateOutput(window: Window, block: (bitmap: Bitmap) -> Boolean) {
            val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
            val bitmap = uiAutomation.takeScreenshot(window)
            if (bitmap != null) {
                block(bitmap)
            } else {
                throw IllegalArgumentException("Unable to obtain bitmap from screenshot")
            }
        }

        fun validateOutput(block: (bitmap: Bitmap) -> Boolean) {
            var sleepDurationMillis = 1000L
            var success = false
            for (i in 0..3) {
                val bitmap = getScreenshot(InstrumentationRegistry.getInstrumentation())
                success = block(bitmap)
                if (!success) {
                    SystemClock.sleep(sleepDurationMillis)
                    sleepDurationMillis *= 2
                } else {
                    break
                }
            }
            Assert.assertTrue(success)
        }

        fun checkNullCrop(
            bitmap: Bitmap,
            coord: IntArray
        ): Boolean {
            // check top left
            return Color.RED ==
                bitmap.getPixel(coord[0], coord[1]) &&
                // check top right
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH - 1,
                    coord[1]
                ) &&
                // check  bottom right
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH - 1,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT - 1
                ) &&
                // check bottom left
                Color.RED ==
                bitmap.getPixel(
                    coord[0],
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT - 1
                ) &&
                // check center
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH / 2,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT / 2
                )
        }

        fun checkStandardCrop(
            bitmap: Bitmap,
            coord: IntArray
        ): Boolean {
            // check left crop
            return Color.BLACK ==
                bitmap.getPixel(
                    coord[0] + 19,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT / 2
                ) &&
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + 20,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT / 2
                ) &&
                // check top crop
                Color.BLACK ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH / 2,
                    coord[1] + 29
                ) &&
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH / 2,
                    coord[1] + 30
                ) &&
                // check right crop
                Color.BLACK ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH - 10,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT / 2
                ) &&
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT - 11,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT / 2
                ) &&
                // check bottom crop
                Color.BLACK ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH / 2,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT - 40
                ) &&
                Color.RED ==
                bitmap.getPixel(
                    coord[0] + SurfaceControlWrapperTestActivity.DEFAULT_WIDTH / 2,
                    coord[1] + SurfaceControlWrapperTestActivity.DEFAULT_HEIGHT - 41
                )
        }

        fun getScreenshot(instrumentation: Instrumentation): Bitmap {
            val uiAutomation = instrumentation.uiAutomation
            val screenshot = uiAutomation.takeScreenshot()
            return screenshot
        }

        fun getSolidBuffer(width: Int, height: Int, color: Int): HardwareBuffer {
            return nGetSolidBuffer(width, height, color)
        }
        fun getQuadrantBuffer(
            width: Int,
            height: Int,
            colorTopLeft: Int,
            colorTopRight: Int,
            colorBottomRight: Int,
            colorBottomLeft: Int
        ): HardwareBuffer {
            return nGetQuadrantBuffer(
                width,
                height,
                colorTopLeft,
                colorTopRight,
                colorBottomRight,
                colorBottomLeft
            )
        }

        private external fun nGetSolidBuffer(width: Int, height: Int, color: Int): HardwareBuffer
        private external fun nGetQuadrantBuffer(
            width: Int,
            height: Int,
            colorTopLeft: Int,
            colorTopRight: Int,
            colorBottomRight: Int,
            colorBottomLeft: Int
        ): HardwareBuffer

        init {
            System.loadLibrary("graphics-core")
        }
    }
}
